create or replace package body m4o_code_generator as

  C_MODULE constant m4o_module := new m4o_module('m4o_code_generator');

  subtype lines_t is m4osys_dynsql.lines_t;

  p_lines lines_t;

  -- ===========================================================================
  procedure init
  is
  begin
    p_lines.delete;
  end;
  -- ===========================================================================
  procedure w(i_src in varchar2)
  is
    v_lines m4o_v2tab;
  begin
    v_lines := m4o_v2.split(i_src,chr(10));
    for i in 1 .. v_lines.count loop
      p_lines(p_lines.count+1) := v_lines(i);
    end loop;
  end;
  -- ===========================================================================
  procedure execute_code_if_different(
    i_owner in varchar2,
    i_type  in varchar2,
    i_name  in varchar2)
  is
    v_pc     m4o_context := C_MODULE.proc('execute_code_if_different',
                                           m4o_v2tab(i_owner,
                                                 i_type,
                                                 i_name));
    v_db_src  lines_t;
    v_differs boolean;
  begin
    v_pc.do('Load current source code from db');
    select case line
             when 1 then 'create or replace '
             else null
           end||
           replace(text,
                   chr(10),
                   null)
    bulk collect into v_db_src
    from all_source
    where type         = i_type
    and   name         = i_name
    and   owner        = i_owner
    and   length(text) > 0
    order by line;

    if v_db_src.count = 0 then
      v_pc.do('Does not exist - execute new');
      m4osys_dynsql.create_any_package(p_lines);
    else
      for i in 1 .. v_db_src.count loop
        if p_lines.count < i
           or v_db_src(i)||'x' <> p_lines(i)||'x' then
          v_pc.do('Different code - execute new');
          m4osys_dynsql.create_any_package(p_lines);
          exit;
        else
          v_pc.log('EQ: '||v_db_src(i));
        end if;
      end loop;
    end if;

    v_pc.do('Emit any errors');
    for v_err in (with e as (
                    select owner,type,name,line,position,text
                    from all_errors
                    where owner = i_owner
                    and   type  = i_type
                    and   name  = i_name)
                  select s.line+0.1 pkb_script_order,
                         lpad(s.line,4)
                      || ': '
                      || s.text text
                  from all_source s,
                       (select distinct owner,type,name,line from e) e
                  where e.owner = s.owner
                  and   e.type  = s.type
                  and   e.name  = s.name
                  and   (s.line =1
                         or s.line between e.line-3 and e.line+3)
                  union
                  select line+0.2,
                         '####: '
                      || case when position > 1
                               and row_number() over (partition by line order by 1)=1 then
                             rpad(lpad('^',position,'-'),80,'-')
                          || chr(10)
                          || '####: '
                         end
                      || text
                  from e
                  order by 1) loop
      dbms_output.put_line(rtrim(v_err.text,chr(10)));
    end loop;
  end;
end;
/


